package domain;

import domain.player.*;
import domain.player.ai.AI;
import java.util.Random;

/**
 * GameManager handles the game play. It constist of a game loop that runs
 * as long as the game haven't finished. Within the loop the GameManager
 * alternates the players and invokes the current player's next move.
 */
public class GameManager {

	private GameGrid gameGrid;
	private DomainController logicController;
	private Player player1;
	private Player player2;
	private int currentPlayerNum;
        private boolean debug = false;

	public GameManager(DomainController logicController, GameGrid gameGrid) {
		this.gameGrid = gameGrid;
		this.logicController = logicController;
	}

	/** Starts the game by executing the GameLoop class */
	public void startGame() {
		gameLoop();
  	}

	/** GameLoop class utilizing the SwingWorker class */
	private void gameLoop() {
		new Thread(new Runnable() {

			@Override
			public void run() {
				currentPlayerNum = 1;
				gameGrid = logicController.getGameGrid();

				while (!hasEnded()) {
					logicController.setCurrentPlayerFrameName(getCurrentPlayer());
					makeNextMove();
				}

				Player winner = getWinner();
				if (winner != null) {
					logicController.presentWinnerBoard();
					logicController.showWinnerDialog(winner);
				} else if (gameGrid.isTie()) {
					logicController.showDrawnDialog();
				}
			}
		}).start();
	}

	/** Add players to the game
	 * @param player1
	 * @param player2
	 */
	public void addPlayers(Player player1, Player player2) {
		this.player1 = player1;
		this.player2 = player2;

		randomizeStartPlayer();
	}

	/** Randomize start player */
	public void randomizeStartPlayer() {
		if (player1 != null && player2 != null) {
			currentPlayerNum = (new Random().nextInt() % 2 == 0 ? 1 : 2);
		}
	}

	/** Returns a Player object corresponding to playerNum */
	public Player getPlayer(int playerNum) {
		return (playerNum % 2 == 0 ? player2 : player1);
	}

	/** Returns the Player object for the current player */
	public Player getCurrentPlayer() {
		return (currentPlayerNum % 2 == 0 ? player2 : player1);
	}

	/** Change the current player */
	public void changeCurrentPlayer() {
		currentPlayerNum = getCurrentPlayer().getDiscID().
				equals(player1.getDiscID()) ? 2 : 1;
	}

	/** Executes the next move */
	public boolean makeNextMove() {
		int column = logicController.getNextMove();

		if (gameGrid.isValidMove(column)) {
                        // used for debug
                        if(getCurrentPlayer().getType() == PlayerType.COMPUTER && debug){
                            int nrOfMovesMM = 0;
                            int nrOfMovesMMABP = 0;
                            int tempMove = 0;
                            int score = 0;
                            Computer p = (Computer)getCurrentPlayer();
                            if(p.getAIType() == AI.AI_MINIMAX){
                                nrOfMovesMM = p.getNrOfEvaluatedMoves();
                                System.out.println("score " + p.getScoreForMove());
                                p.setAIType(AI.AI_MINMAX, false, false, p.getMovesAhead());
                                System.out.println("setting to AI_MINMAX");
                                tempMove = logicController.getNextMove();
                                nrOfMovesMMABP = p.getNrOfEvaluatedMoves();
                                score = p.getScoreForMove();
                                p.setAIType(AI.AI_MINIMAX, false, false, p.getMovesAhead());
                            } else{
                                nrOfMovesMMABP = p.getNrOfEvaluatedMoves();
                                System.out.println("score " + p.getScoreForMove());
                                p.setAIType(AI.AI_MINIMAX, false, false, p.getMovesAhead());
                                System.out.println("setting to AI_MINIMAX");
                                logicController.getNextMove();
                                nrOfMovesMM = p.getNrOfEvaluatedMoves();
                                score = p.getScoreForMove();
                                p.setAIType(AI.AI_MINMAX, false, false, p.getMovesAhead());
                            }
                            
                            System.out.println("score2 " + score);
                            System.out.println("Moves = " + column + " and " + tempMove);
                            logicController.presentMoveWithAndWithout(score, nrOfMovesMM, nrOfMovesMMABP);
                            
                        }
                        
			logicController.addDisc(column);
			changeCurrentPlayer();
			return true;
		}
		return false;
	}

	/** Returns true if the current game has ended */
	private boolean hasEnded() {
		return gameGrid.isTie() || gameGrid.hasWon();
	}

	/** Returns the winner as a Player object, null if none */
	private Player getWinner() {
		if (gameGrid.getWinner() != Disc.NONE) {
			return (player1.getDiscID() == gameGrid.getWinner()
					? player1 : player2);
		}
		return null;
	}

    public void setDebug(boolean debug) {
        this.debug = (this.debug == debug) ? invers(debug) : debug;
    }

    private boolean invers(boolean debug){
        return debug == true ? false : true;
    }
    
    public void setGameGrid(GameGrid gameGrid){
        this.gameGrid = gameGrid;
    }
}